package work.linruchang.util;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.HexUtil;
import cn.hutool.core.util.StrUtil;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.UUID;

/**
 * 增强的RSA密钥处理工具
 *
 * @author LinRuChang
 * @version 1.0
 * @date 2020/09/27
 * @since 1.8
 **/
public class EnhanceRSAUtil {


    public static void main(String[] args) throws Exception {
        //RSAUtil.generateKey("C:\\Users\\lrc\\Desktop\\test\\publicKey.txt", "C:\\Users\\lrc\\Desktop\\test\\privateKey.txt", "3213");
        //getPublicKey(readFile("C:\\Users\\lrc\\Desktop\\test\\publicKey.txt"));
    }

    /**
     * 生成一个钥匙对在对应的磁盘路径中
     *
     * @param publicKeyPath  公钥路径
     * @param privateKeyPath 私钥路径
     */
    public static void generateKey(String publicKeyPath, String privateKeyPath) throws Exception {
        generateKey(publicKeyPath, privateKeyPath, UUID.randomUUID().toString());
    }

    /**
     * 生成一个钥匙对在对应的磁盘路径中
     *
     * @param publicKeyPath  公钥路径
     * @param privateKeyPath 私钥路径
     * @param seed           种子
     */
    public static void generateKey(String publicKeyPath, String privateKeyPath, String seed) throws Exception {

        //KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
        //SecureRandom secureRandom = new SecureRandom(seed.getBytes());
        //keyPairGenerator.initialize(1024, secureRandom);
        //
        //KeyPair keyPair = keyPairGenerator.genKeyPair();
        KeyPair keyPair = generateKey(seed);

        PublicKey publicKey = keyPair.getPublic();
        PrivateKey privateKey = keyPair.getPrivate();
        byte[] publicKeyEncoded = publicKey.getEncoded();
        byte[] privateKeyEncoded = privateKey.getEncoded();

        writeFile(publicKeyPath, publicKeyEncoded);
        writeFile(privateKeyPath, privateKeyEncoded);

    }

    /**
     * 生成RSA密钥对
     *
     * @param seed  种子
     */
    public static KeyPair generateKey(String seed) throws NoSuchAlgorithmException {
        seed = StrUtil.blankToDefault(seed, cn.hutool.core.lang.UUID.fastUUID().toString(true));
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
        SecureRandom secureRandom = new SecureRandom(seed.getBytes());
        keyPairGenerator.initialize(1024, secureRandom);
        return keyPairGenerator.genKeyPair();
    }

    /**
     * 生成RSA密钥对
     */
    public static KeyPair generateKey() throws NoSuchAlgorithmException {
        return generateKey(null);
    }

    /**
     * 从文件信息读取转为字节数组byte[]
     * @param fileName
     * @return
     * @throws IOException
     */
    public static byte[] readFile(String fileName) throws IOException {
        return Files.readAllBytes(new File(fileName).toPath());
    }



    public static PublicKey getPublicKey(String fileName) throws Exception {
        return getPublicKey(readFile(fileName));
    }

    /**
     * 将公钥的十六进制字符串转化成公钥对象
     * @param publicKeyHexStr 公钥的16进制形式
     * @return
     * @throws Exception
     */
    public static PublicKey getPublicKeyByHexStr(String publicKeyHexStr) throws Exception {
        Assert.notBlank(publicKeyHexStr,"公钥的16进制的字符串缺失");
        return getPublicKey(HexUtil.decodeHex(publicKeyHexStr));
    }

    /**
     * 将公钥的字节数组转为公钥对象
     * @param keyEncoded
     * @return
     * @throws Exception
     */
    public static PublicKey getPublicKey(byte[] keyEncoded) throws Exception {
        X509EncodedKeySpec spec = new X509EncodedKeySpec(keyEncoded);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        return keyFactory.generatePublic(spec);
    }




    public static PrivateKey getPrivateKey(String fileName) throws Exception {
        return getPrivateKey(readFile(fileName));
    }

    /**
     * 将私钥的字节数组转为私钥对象
     * @param keyEncoded
     * @return
     * @throws Exception
     */
    public static PrivateKey getPrivateKey(byte[] keyEncoded) throws Exception {
        PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyEncoded);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        return keyFactory.generatePrivate(spec);
    }

    /**
     * 将私钥的十六进制字符串转化成私钥对象
     * @param privateKeyHexStr 私钥的十六进制字符串
     * @return
     * @throws Exception
     */
    public static PrivateKey getPrivateKeyByHexStr(String privateKeyHexStr) throws Exception {
        return getPrivateKey(HexUtil.decodeHex(privateKeyHexStr));
    }


    /**
     * 将密钥持久化到对应的文件中
     * @param keyPath
     * @param keyEncoded
     * @throws Exception
     */
    public static void writeFile(String keyPath, byte[] keyEncoded) throws Exception {

        File file = new File(keyPath);

        if (!file.exists()) {
            file.getParentFile().mkdirs();
            file.createNewFile();

        }

        FileOutputStream fos = new FileOutputStream(keyPath);
        fos.write(keyEncoded, 0, keyEncoded.length);
        fos.close();

        //上述三行代码可使用这一行代码代替
        //Files.write(file.toPath(), keyEncoded);
    }


}